home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Dos / VARIOS / pascal / MENU.SWG / 0002_RA-FD alike Menu unit.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1996-02-21  |  17.0 KB  |  686 lines

  1. {
  2. I saw someone could use a menu unit like the one used with RA/FD/ALLFIX..
  3. Well... I have one... :
  4.  
  5. ·oO BEGIN Menus.Pas Oo·
  6. (* This unit is (c) 1995 by Archangel/DMA
  7.    You can use this unit, or parts of it in your own programs as
  8.    long as you mention my name somewhere (I didn't code it all for
  9.    fun you know =])
  10.  
  11.    It's a pretty straightforward unit, if you don't get it, try to
  12.    look at the code some more and probably you'll understand. Or you
  13.    can read the comments.
  14.  
  15.    About comments, there are not much comments since I'm not good at
  16.    commenting my own sources...
  17.  
  18. *)
  19. {$G+,F+,X+,V-,R-,O+}
  20. {$M 8192,0,128000}                           { Set up some local stack space }
  21. Unit RAMenu;
  22. Interface
  23. Type
  24.   SaveRecord = Record                         { Record used for 'pushscreen' }
  25.                  Case UseDisk: Boolean of                        { Use disk? }
  26.                    TRUE : (FName: string[12]);              { Yes? What file }
  27.                    FALSE: (MemPtr: Pointer);                    { No? Where? }
  28.                End;
  29.   SaveStackType = array[1..50] of SaveRecord;                   { Save stack }
  30.   SubMenuRecord = record                     { Record used to store submenus }
  31.                     ItemName : string[40];        { Name of item (displayed) }
  32.                     ItemProc : Procedure;     { Pointer to procedure to exec }
  33.                     ItemHelp : string[79];                    { The helpline }
  34.                   end;
  35.   SubMenuType = array[1..20] of SubMenuRecord;                 { One submenu }
  36.   MainMenuRecord = record             { Record used to store main menu items }
  37.                      ItemName : string[20];
  38.                      ItemHelp : string[79];
  39.                      SubMenu  : SubMenuType;      { Submenu of this mainmenu }
  40.                    end;
  41.   MainMenuType = array[1..10] of MainMenuRecord;  { The total menu structure }
  42.   VRecord = record                                       { Video memory type }
  43.               VChar : char;
  44.               VAttr : byte;
  45.             End;
  46.   VMemType = array[1..25,1..80] of VRecord;                   { Video memory }
  47.   TabType = array[1..10] of Byte;                             { A table type }
  48.   TabType2 = array[1..20] of Byte;                            { A table type }
  49.  
  50. Var
  51.   Menu        : ^MainMenuType;
  52.   XTab        : TabType;
  53.   SubRemP     : TabType2;
  54.   ColorMem    : VMemType absolute $B800:0000;
  55.   MonoMem     : VMemType absolute $B000:0000;
  56.   Mono        : Boolean;
  57.   VideoSegment: Word;
  58.   OldExit     : Pointer;
  59.   CommentColor: byte;                                   { Color of helplines }
  60. Const
  61.   StackMaxMem : Byte=10;
  62.  
  63. (* STACKMAXMEM
  64.  
  65.    This is something to consider, this constant holds the amount of screens
  66.    saved in memory before the unit starts saving on disks. Since I've only
  67.    built in total screen saving, 10 screens will take up 40000 bytes. If
  68.    you need that memory either set it to a lower value or set it to '1'.
  69.  
  70. *)
  71.  
  72. Function GetAttr(X,Y: Byte): Byte;
  73. { Get attribute from a position }
  74. Procedure SetAttr(X,Y,Attr: byte);
  75. { Set attribute on a position }
  76.  
  77. Procedure VWriteCh(Ch: char;x,y: byte);
  78. { Write a character to the video memory with the attribute stored in
  79.   'textattr'}
  80. Procedure VWriteStr(S: string;fg,bg,x,y: byte);
  81. { Write a string to the video memory with the colors 'fg' and 'bg' and
  82.   start writing on 'x', 'y' }
  83. Procedure Color(fg,bg: byte);
  84. { Set the current colors to 'fg' and 'bg' }
  85.  
  86. Procedure DrawBox(x1,y1,x2,y2,bfg,bbg,wfg,wbg: byte;Title: string;TFG,TBG:
  87. byte);{ Draw a box, variables are:
  88.  
  89.   x1,y1,x2,y2: Upper left and lower right corners
  90.   bfg,bbg    : Color of the box
  91.   wfg,wbg    : Color of the inside of the box
  92.   Title      : A title to give to the box, special chars are:
  93.                '!'  - Put title on upper left side
  94.                '@'  - Centre title on upper side
  95.                '#'  - Put title on upper right side
  96.   Tfg,Tbg    : Color of the title
  97.  
  98.   Example:
  99.  
  100.   DrawBox(1,1,80,25,11,0,7,0,'!Upper left',15,0);
  101. }
  102.  
  103. Procedure ErrorMessage(Message: string);
  104. { Displays an errormessage }
  105. Procedure Message(Message: string);
  106. { Displays a normal message }
  107. Function AskBox(S,T: String;bfg,bbg,tfg,tbg: Byte): Boolean;
  108. { Ask a Yes/No question, returns TRUE on yes }
  109.  
  110. Procedure CursorOff;
  111. { Turns cursor off }
  112. Procedure CursorOn;
  113. { Turns cursor on }
  114.  
  115. Function TopMenu: Byte;
  116. { Start the mainmenu }
  117. Procedure SubMenu(Var Which: Byte);
  118. { Execute a submenu }
  119. Procedure SetXTab;
  120. { Used to get a table for the menu positions }
  121.  
  122. Procedure PopScreen;
  123. { Save a screen to savestack}
  124. Procedure PushScreen;
  125. { Restore a screen from savestack }
  126.  
  127. Procedure HelpLine(S: string);
  128. { Prints a helpline on line 25 }
  129. Procedure ClearHelp;
  130. { Clear line 25}
  131.  
  132. Implementation
  133. Uses Crt,Dos;
  134. Var
  135.   SaveCurHi   : Byte; { High scan line of cursor }
  136.   SaveCurLo   : Byte; { Low scanline of cursor }
  137.  
  138.   RemTop      : Byte; { Temp save for top menu position }
  139.   SaveStack   : ^SaveStackType; { Screen save stack }
  140.   SaveStackPtr: Byte; { Screen save stack pointer }
  141.  
  142. Procedure WaitKey;  { Waits for a key }
  143. Begin
  144.   ReadKey;
  145. End;
  146.  
  147. Function FStr(A: Longint): string; { Turns a longint to a string }
  148. Var
  149.   Temp : string;
  150. Begin
  151.   Str(A,Temp);
  152.   FStr :=Temp;
  153. End;
  154.  
  155. Function FVal(S: string): Longint; { Turns a string into a longint }
  156. Var
  157.   Temp: Longint;
  158.   Code: Integer;
  159. Begin
  160.   Val(S,Temp,Code);
  161.   FVal :=Temp;
  162. End;
  163.  
  164. Function ForceBack(s: string): string; { Adds a '\' to a string if it's not
  165. there }Begin
  166.   If S[length(s)]<>'\' then S :=s+'\';
  167.   ForceBack :=s;
  168. End;
  169.  
  170. Function LZ(w : Word) : String;
  171. Var
  172.   S : String;
  173. begin
  174.   Str(w:0,s);
  175.   if Length(s)=1 then s := '0' + s;
  176.   LZ := s;
  177. end;
  178.  
  179. Procedure ClrScr; { Clears the screen, keeping the current unit colors }
  180. Var
  181.   Bak : byte;
  182. Begin
  183.   Bak :=TextAttr;
  184.   TextColor(7);
  185.   TextBackGround(0);
  186.   Crt.ClrScr;
  187.   TextAttr :=Bak;
  188. End;
  189.  
  190. Function Expand(S: string;Len: Byte): String; { Expand a string }
  191. Begin
  192.   Expand :=S;
  193.   If Length(S)>Len then Exit;
  194.   While Length(s)<Len do S :=S+' ';
  195.   Expand :=S;
  196. End;
  197.  
  198. Function BasePath: String; { Get the program's own path }
  199. Var
  200.   P: PathStr;
  201.   D: DirStr;
  202.   N: NameStr;
  203.   E: ExtStr;
  204. Begin
  205.   P :=ParamStr(0);
  206.   FSplit(P,D,N,E);
  207.   BasePath :=ForceBack(FExpand(D));
  208. End;
  209.  
  210. Procedure SetXTab; { Set the XTab for the menus }
  211. Var
  212.   Tel : byte;
  213. Begin
  214.   For Tel :=2 to 10 do XTab[Tel]
  215. :=XTab[Tel-1]+Length(Menu^[Tel-1].ItemName)+2;End;
  216.  
  217. Procedure PushScreen;
  218. Var
  219.   SaveStackFile : File of VMemType;
  220. Begin
  221.   If SaveStackPtr=50 then
  222.   Begin
  223.     ErrorMessage('Screen save stack overflow');
  224.     Halt(10);
  225.   End;
  226.   If (MaxAvail<10000) or (SaveStackPtr>StackMaxMem) then
  227.   With SaveStack^[SaveStackPtr] do
  228.   Begin
  229.     UseDisk :=TRUE;
  230.     FName :=BasePath+'SAV'+FStr(SaveStackPtr)+'.TMP';
  231.     Assign(SaveStackFile,FName);
  232.     {$i-}
  233.     Rewrite(SaveStackFile);
  234.     {$i+}
  235.     If IOResult<>0 then
  236.     Begin
  237.       ErrorMessage('Cannot open temporary file for writing');
  238.       Halt(10);
  239.     End;
  240.     Case Mono of
  241.       TRUE : Write(SaveStackFile,MonoMem);
  242.       FALSE: Write(SaveStackFile,ColorMem);
  243.     End;
  244.     Close(SaveStackFile);
  245.   End
  246.   Else With SaveStack^[SaveStackPtr] do
  247.   Begin
  248.     GetMem(MemPtr,4000);
  249.     Case Mono of
  250.       TRUE : Move(MonoMem,MemPtr^,4000);
  251.       FALSE: Move(ColorMem,MemPtr^,4000);
  252.     End;
  253.   End;
  254.   Inc(SaveStackPtr);
  255. End;
  256.  
  257. Procedure PopScreen;
  258. Var
  259.   SaveStackFile : File of VMemType;
  260.   Temp          : VMemType;
  261. Begin
  262.   If SaveStackPtr=1 then Exit;
  263.   Dec(SaveStackPtr);
  264.   With SaveStack^[SaveStackPtr] do
  265.   Begin
  266.     If UseDisk then
  267.     Begin
  268.       Assign(SaveStackFile,FName);
  269.       {$i-}
  270.       Reset(SaveStackFile);
  271.       {$i+}
  272.       If IOResult<>0 then
  273.       Begin
  274.         ErrorMessage('Cannot open temporary file for reading');
  275.         Halt(10);
  276.       End;
  277.       Read(SaveStackFile,Temp);
  278.       Close(SaveStackFile);
  279.       Case Mono of
  280.         TRUE : Move(Temp,MonoMem,4000);
  281.         FALSE: Move(Temp,ColorMem,4000);
  282.       End;
  283.     End else
  284.     Begin
  285.       Case Mono of
  286.         TRUE : Move(MemPtr^,MonoMem,4000);
  287.         FALSE: Move(MemPtr^,ColorMem,4000);
  288.       End;
  289.       FreeMem(MemPtr,4000);
  290.       MemPtr :=NIL;
  291.     End;
  292.   End;
  293. End;
  294.  
  295. Procedure CursorOff; assembler;
  296. ASM
  297.   MOV           AX,0300h
  298.   MOV           BH,0
  299.   INT           10h
  300.   MOV           [SaveCurHi],CH
  301.   MOV           [SaveCurLo],CL
  302.   MOV           AX,0100h
  303.   MOV           CX,2000h
  304.   INT           10h
  305. END;
  306.  
  307. Procedure CursorOn; assembler;
  308. ASM
  309.   MOV           AX,0100h
  310.   MOV           CH,[SaveCurHi]
  311.   MOV           CL,[SaveCurLo]
  312.   INT           10h
  313. END;
  314.  
  315. Procedure Color(fg,bg: byte);
  316. Begin
  317.   TextColor(Fg);
  318.   TextBackground(bg);
  319. End;
  320.  
  321. Function GetAttr(X,Y: Byte): Byte;
  322. Begin
  323.   Case Mono of
  324.     TRUE : GetAttr :=MonoMem[Y,X].VAttr;
  325.     FALSE: GetAttr :=ColorMem[Y,X].VAttr;
  326.   End;
  327. End;
  328.  
  329. Procedure SetAttr(X,Y,Attr: byte);
  330. Begin
  331.   Case Mono of
  332.     TRUE : MonoMem[Y,X].VAttr :=Attr;
  333.     FALSE: ColorMem[Y,X].VAttr :=Attr;
  334.   End;
  335. End;
  336.  
  337. Function MakeAttr(Fg,Bg: Byte): Byte; { Creates an attribute out of a
  338. foreground/background color }Begin
  339.   MakeAttr :=Fg+16*Bg;
  340. End;
  341.  
  342. Procedure SetAttrRange(X1,X2,Y,Attr: Byte); { Sets the attribute over a range
  343. }Var
  344.   Tel : Byte;
  345. Begin
  346.   For Tel :=1 to x2-x1 do SetAttr(x1-1+Tel,Y,Attr);
  347. End;
  348.  
  349. Procedure VWrite(Ch: char;x,y: byte);
  350. Begin
  351.   Case Mono of
  352.     TRUE : With MonoMem[Y,X] do
  353.            Begin
  354.              VChar :=Ch;
  355.              VAttr :=TextAttr;
  356.            End;
  357.     FALSE: With ColorMem[Y,X] do
  358.            Begin
  359.              VChar :=Ch;
  360.              VAttr :=TextAttr;
  361.            End;
  362.   End;
  363. End;
  364.  
  365. Procedure VWriteCh(Ch: char;x,y: byte);
  366. Begin
  367.   VWrite(ch,x,y);
  368. End;
  369.  
  370. Procedure VWriteStr(S: string;fg,bg,x,y: byte);
  371. Var
  372.   Tel : byte;
  373.   Bak : byte;
  374. Begin
  375.   Bak :=TextAttr;
  376.   Color(Fg,Bg);
  377.   For Tel :=1 to length(s) do VWrite(S[Tel],x-1+tel,y);
  378.   TextAttr :=Bak;
  379. End;
  380.  
  381. { Returns the appropriate shade color for the 'drawbox' routine }
  382. Function ReturnShade(X,Y: byte): Byte;
  383. Var
  384.   TA : Byte;
  385.   FG : Byte;
  386.   BG : Byte;
  387. Begin
  388.   TA :=GetAttr(x,y);
  389.   BG :=TA SHR 4;
  390.   FG :=TA-BG;
  391.   If Fg>8 then
  392.   Begin
  393.     Dec(Fg,8);
  394.     Bg :=0;
  395.   End
  396.   else
  397.   Begin
  398.     Fg :=8;
  399.     Bg :=0;
  400.   End;
  401.   ReturnShade :=Fg+(16*Bg);
  402. End;
  403.  
  404. Procedure DrawBox(x1,y1,x2,y2,bfg,bbg,wfg,wbg: byte;Title: string;TFG,TBG:
  405. byte);Var
  406.   Tel,Tel2: byte;
  407.   A,B: Word;
  408. Begin
  409.   A :=WindMax;
  410.   B :=WindMin;
  411.   Color(wfg,wbg);
  412.   Window(x1,y1,x2,y2);
  413.   Crt.ClrScr;
  414.   WindMax :=A;
  415.   WindMin :=B;
  416.   Color(bfg,bbg);
  417.   For Tel :=1 to x2-x1 do
  418.   Begin
  419.     VWriteCh('═',x1-1+tel,y1);
  420.     VWriteCh('═',x1-1+tel,y2);
  421.   End;
  422.   For Tel :=1 to y2-y1 do
  423.   Begin
  424.     Color(bfg,bbg);
  425.     VWriteCh('│',x1,y1-1+tel);
  426.     Color(bfg,bbg);
  427.     VWriteCh('│',x2,y1-1+tel);
  428.   End;
  429.   VWriteCh('╛',x2,y2);
  430.   VWriteCh('╕',x2,y1);
  431.   VWriteCh('╘',x1,y2);
  432.   VWriteCh('╒',x1,y1);
  433.   For Tel :=1 to x2-x1 do SetAttr(x1+Tel,y2+1,ReturnShade(x1+Tel,y2+1));
  434.   For Tel :=1 to (y2-y1)+1 do SetAttr(x2+1,y1+Tel,ReturnShade(x2+1,y1+Tel));
  435.   If Title<>'' then
  436.   Begin
  437.     If Title[1]='!' then VWriteStr(' '+Copy(Title,2,Length(Title)-1)+'',Tfg,Tbg,x1+2,y1);
  438.     If Title[1]='@' then VWriteStr(''+Copy(Title,2,Length(Title)-1)+' ',Tfg,Tbg,x2-Length(Title)-2,y1);
  439.     If Title[1]='#' then VWriteStr(' '+Copy(Title,2,Length(Title)-1)+'',Tfg,Tbg,x1+((x2-x1) div 2)-(Length(Title) div 2),y1);
  440.     End;
  441. End;
  442.  
  443. Procedure HelpLine(S: string);
  444. Begin
  445.   VWriteStr(Expand(S,79),CommentColor,0,2,25);
  446. End;
  447.  
  448. Procedure ClearHelp;
  449. Begin
  450.   VWriteStr(Expand(' ',79),7,0,2,25);
  451. End;
  452.  
  453. Procedure Message(Message: string);
  454. Const
  455.   Prompt = 'Press any key';
  456. Var
  457.   A   : Byte;
  458. Begin
  459.   PushScreen;
  460.   ClearHelp;
  461.   Message :=Message+' - '+Prompt;
  462.   A :=40-(Length(Message) div 2);
  463.   DrawBox(a,11,a+Length(Message)+1,15,12,4,14,4,'',15,4);
  464.   VWriteStr(Message,14,4,a+1,13);
  465.   WaitKey;
  466.   PopScreen;
  467. End;
  468.  
  469. Procedure ErrorMessage(Message: string);
  470. Const
  471.   Prompt = 'Press any key';
  472. Var
  473.   A   : Byte;
  474. Begin
  475.   PushScreen;
  476.   ClearHelp;
  477.   Message :=Message+' - '+Prompt;
  478.   A :=40-(Length(Message) div 2);
  479.   DrawBox(a,11,a+Length(Message)+1,15,12,4,14,4,'!ERROR',15,4);
  480.   VWriteStr(Message,14,4,a+1,13);
  481.   WaitKey;
  482.   PopScreen;
  483. End;
  484.  
  485. Function AskBox(S,T: String;bfg,bbg,tfg,tbg: Byte): Boolean;
  486. Var
  487.   A   : Byte;
  488.   Ch  : Char;
  489. Begin
  490.   PushScreen;
  491.   A :=40-(Length(S) div 2);
  492.   DrawBox(a,12,a+Length(S)+1,14,Bfg,Bbg,Tfg,Tbg,T,Tfg,TBg);
  493.   VWriteStr(S,Tfg,Tbg,a+1,13);
  494.   Repeat
  495.     Ch :=UpCase(ReadKey);
  496.   Until Ch in ['Y','N'];
  497.   AskBox :=(Ch='Y');
  498.   PopScreen;
  499. End;
  500.  
  501. { Used internally for the submenu's }
  502. Function GetLastX(SubRec: SubMenuType): Byte;
  503. Var
  504.   Temp : Byte;
  505.   Tel  : Byte;
  506. Begin
  507.   Temp :=0;
  508.   For Tel :=1 to 20 do with SubRec[Tel] do If ItemName<>'' then If
  509. Length(ItemName)>Temp then Temp :=Length(ItemName);  GetLastX :=Temp;
  510. End;
  511.  
  512. { Used internally for the submenu's }
  513. Function GetLastY(SubRec: SubMenuType): Byte;
  514. Var
  515.   Temp : Byte;
  516.   Tel  : Byte;
  517. Begin
  518.   Temp :=0;
  519.   For Tel :=1 to 20 do With SubRec[Tel] do If ItemName<>'' then Inc(Temp);
  520.   GetLastY :=Temp;
  521. End;
  522.  
  523. { Used internally for the main menu }
  524. Function TopItems: Byte;
  525. Var
  526.   Tel : Byte;
  527.   Temp: Byte;
  528. Begin
  529.   Temp :=0;
  530.   For Tel :=1 to 10 do If Menu^[Tel].ItemName<>'' then Inc(Temp);
  531.   TopItems :=Temp;
  532. End;
  533.  
  534. { Draws the main menu }
  535. Procedure DrawTop;
  536. Var
  537.   Tel : Byte;
  538. Begin
  539.   For Tel :=1 to TopItems do VWriteStr(Menu^[Tel].ItemName,7,0,XTab[Tel],1);
  540. End;
  541.  
  542. { Draws a sub menu }
  543. Procedure DrawMenu(Which: Byte;Var LastX,LastY: Byte);
  544. Var
  545.   Tel    : Byte;
  546. Begin
  547.   LastX :=GetLastX(Menu^[Which].SubMenu);
  548.   LastY :=GetLastY(Menu^[Which].SubMenu);
  549.   DrawBox(XTab[Which],2,XTab[Which]+LastX+1,2+LastY+1,11,0,7,0,'',0,0);
  550.   For Tel :=1 to LastY do
  551. VWriteStr(Menu^[Which].SubMenu[Tel].ItemName,7,0,XTab[Which]+1,2+Tel);
  552. DrawTop;  VWriteStr(Menu^[Which].ItemName,1,3,XTab[Which],1);
  553. End;
  554.  
  555. Procedure SubMenu(Var Which: Byte);
  556. Var
  557.   MPos  : Byte;
  558.   OPos  : Byte;
  559.   LastY : Byte;
  560.   LastX : Byte;
  561.   TI    : Byte;
  562.   OW    : Byte;
  563. Begin
  564.   DrawTop;
  565.   PushScreen;
  566.   TI :=TopItems;
  567.   MPos :=SubRemP[Which];
  568.   OPos :=MPos;
  569.   OW :=0;
  570.   DrawMenu(Which,LastX,LastY);
  571.   While True Do
  572.   Begin
  573.  
  574. VWriteStr(Expand(Menu^[Which].SubMenu[MPos].ItemName,LastX),1,7,XTab[Which]+1,2+MPos);
  575. HelpLine(Menu^[Which].SubMenu[MPos].ItemHelp);
  576.     If MPos<>OPos then
  577. VWriteStr(Expand(menu^[Which].SubMenu[OPos].ItemName,LastX),7,0,XTab[Which]+1,2 +OPos);
  578. OPos :=MPos;    OW :=Which;
  579.     Case ReadKey of
  580.       #0: Case ReadKey of
  581.             #80: If MPos<LastY then Inc(MPos) else MPos :=1;
  582.             #77: Begin
  583.                    PopScreen;
  584.                    PushScreen;
  585.                    SubRemP[Which] :=MPos;
  586.                    If Which<TI then Inc(Which) else Which :=1;
  587.                    DrawMenu(Which,LastX,LastY);
  588.                    RemTop :=Which;
  589.                    MPos :=SubRemP[Which];
  590.                    OPos :=MPos;
  591.                  End;
  592.             #75: Begin
  593.                    PopScreen;
  594.                    PushScreen;
  595.                    SubRemP[Which] :=MPos;
  596.                    If Which>1 then Dec(Which) else Which :=TI;
  597.                    DrawMenu(Which,LastX,LastY);
  598.                    RemTop :=Which;
  599.                    MPos :=SubRemP[Which];
  600.                    OPos :=MPos;
  601.                  End;
  602.             #72: If MPos>1 then Dec(MPos) else MPos :=LastY;
  603.           End;
  604.      #13: Begin
  605.             SubRemP[Which] :=MPos;
  606.             PushScreen;
  607.             Menu^[Which].SubMenu[MPos].ItemProc;
  608.             PopScreen;
  609.           End;
  610.      #27: Begin
  611.             SubRemP[Which] :=MPos;
  612.             PopScreen;
  613.             Exit;
  614.           End;
  615.     End;
  616.   End;
  617. End;
  618.  
  619. Function TopMenu: Byte;
  620. Var
  621.   MPos,OPos: Byte;
  622.   TI       : Byte;
  623. Begin
  624.   DrawTop;
  625.   PushScreen;
  626.   MPos :=RemTop;
  627.   OPos :=MPos;
  628.   TI :=TopItems;
  629.   While True do
  630.   Begin
  631.     VWriteStr(Menu^[MPos].ItemName,1,3,XTab[MPos],1);
  632.     HelpLine(Menu^[MPos].ItemHelp);
  633.     If OPos<>MPos then VWriteStr(Menu^[OPos].ItemName,7,0,XTab[OPos],1);
  634.     OPos :=MPos;
  635.     Case ReadKey of
  636.       #0: Case ReadKey of
  637.             #77: If MPos<TI then Inc(MPos) else MPos :=1;
  638.             #75: If MPos>1 then Dec(MPos) else MPos :=TI;
  639.             #80: Begin
  640.                    TopMenu :=MPos;
  641.                    RemTop :=MPos;
  642.                    Exit;
  643.                  End;
  644.           End;
  645.      #13: Begin
  646.             TopMenu :=MPos;
  647.             RemTop :=MPos;
  648.             Exit;
  649.           End;
  650.     End;
  651.   End;
  652. End;
  653.  
  654. Procedure ExitProcedure;
  655. Var
  656.   Tel : byte;
  657.   T   : file;
  658. Begin
  659.   Color(7,0);
  660.   Crt.ClrScr;
  661.   CursorOn;
  662. End;
  663.  
  664. Var
  665.   Tel : byte;
  666.  
  667. Begin
  668.   Case LastMode of
  669.     7: VideoSegment :=$B000;
  670.     3: VideoSegment :=$B800;
  671.     else VideoSegment :=$B800;
  672.   End;
  673.   OldExit :=ExitProc;
  674.   ExitProc :=@ExitProcedure;
  675.   CursorOff;
  676.   SaveStackPtr :=1;
  677.   XTab[1] :=2;
  678.   FillChar(SubRemP,SizeOf(SubRemP),1);
  679.   RemTop :=1;
  680.   New(Menu);
  681.   New(SaveStack);
  682.   FillChar(SaveStack^,SizeOf(SaveStack^),0);
  683.   FillChar(Menu^,SizeOf(Menu^),0);
  684.   CommentColor :=7;
  685. End.
  686.